#!/usr/bin/env python
# coding=utf-8


import os
import sys
import re
import time
import struct


def read_from_text(filename, version):
	timeNow = time.localtime()[:6] + (int(time.time()%1 * 1000),)
	# file struct
	fileStruct = {'Version': version,
			# Date (year, month, day, hour, minute, second, ms)
			'Date': timeNow,
			'Declaration': 'VRMP',
			'OffsetToData': 24,
			'Records': {}
			}
	f = open(filename)
	for line in f:
		if line.strip() == '':
			print('Empty Line!!')
			continue
		textFields = line.strip().split('\t')
		ids = textFields[0]
		rds = tuple(textFields[1:])
		if re.match(r'0[xX][\dA-Fa-f]+', ids):
			id = int(ids, 16)
		else:
			id = int(ids)
		assert(not fileStruct['Records'].has_key(id))
		fileStruct['Records'][id] = rds
	return fileStruct

def write_to_data_file(filename, fileStruct):
	def Num2BCD(num):
		# 2 digit number to one byte compressed BCD
		assert(isinstance(num, int) or isinstance(num, long))
		assert(num < 100 and num >= 0)
		return chr(int(str(num), 16))

	# version
	version = (fileStruct['Version'] + '\0'*4)[:4]
	t = fileStruct['Date']
	# time
	timeNow = Num2BCD(int(t[0]/100)) + Num2BCD(t[0]%100) + Num2BCD(t[1]) + Num2BCD(t[2]) \
			+ Num2BCD(t[3]) + Num2BCD(t[4]) + Num2BCD(t[5]) + Num2BCD(int(t[6]/10))
	# declaration
	declaration = fileStruct['Declaration']
	# record number
	recordNum = len(fileStruct['Records'])
	# offset to data
	dataOffset = fileStruct['OffsetToData']
	assert(dataOffset == 24)

	allRecordId = list(fileStruct['Records'].keys())
	allRecordId.sort()
	allRecordId = tuple(allRecordId)

	# record size, sum of all strings' length and 1 (string number) and "\0"
	# string number of each record
	allRecordStrNum = tuple(len(fileStruct['Records'][id]) for id in allRecordId)
	# string of each record
	allRecordStr = tuple(str.join(' / ', fileStruct['Records'][id]) for id in allRecordId)
	# size of each record, string, '\0', length, string number
	allRecordSize = tuple(len(s)+3 for s in allRecordStr)

	# check
	assert(len(version) == 4)
	assert(len(timeNow) == 8)
	assert(declaration == 'VRMP')
	assert(all(size<256 for size in allRecordSize))

	def OffsetOfRecord(n):
		return 24 + 8 * recordNum + sum(allRecordSize[:n]) 
	def DW2BIN(dw):
		return struct.pack('>I', dw)
	def N2BYTE(n):
		return struct.pack('>B', n)

	f = open(filename, 'wb')
	f.write(version)
	f.write(timeNow)
	f.write(declaration)
	f.write(DW2BIN(recordNum))
	f.write(DW2BIN(dataOffset))
	assert(f.tell() == 24)
	# write offset table
	for n in range(len(allRecordId)):
		f.write(DW2BIN(allRecordId[n]))
		f.write(DW2BIN(OffsetOfRecord(n)))
	# write data
	for n in range(len(allRecordId)):
		assert(f.tell() == OffsetOfRecord(n))
		f.write(N2BYTE(allRecordSize[n]-1))
		f.write(N2BYTE(allRecordStrNum[n]))
		f.write(allRecordStr[n])
		f.write('\0')
	f.close()


def main():
	if len(sys.argv) < 3 or len(sys.argv) > 4:
		print('Usage:')
		print('mk_MltPhoneme.py inputfile ver (outputfilename)')
		return
	inputfilename = sys.argv[1]
	ver = sys.argv[2]
	if len(sys.argv) == 4:
		outputfilename = sys.argv[3]
	else:
		outputfilename = inputfilename + 'mltphn'
	fs = read_from_text(inputfilename, ver)
	write_to_data_file(outputfilename, fs)
	print('OK')

if __name__ == '__main__':
	main()

